package com.lingyue.cpd.test.lock;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author deep.wu
 * @version 1.0 on 2020-04-21 00:16.
 */
@Slf4j
public class ReentrantLockTest4 {

    /**
     * 限时等待
     * 这个是什么意思呢？也就是通过我们的tryLock方法来实现，可以选择传入时间参数，表示等待指定的时间，
     * 无参则表示立即返回锁申请的结果：true表示获取锁成功，false表示获取锁失败。我们可以将这种方法用来解决死锁问题。
     * 首先还是测试代码，不过在这里我们不需要再去中断其中的线程了，我们直接看线程类是如何实现的
     */
    static Lock lock1 = new ReentrantLock();
    static Lock lock2 = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new ThreadDemo(lock1, lock2), "thread-A");
        Thread thread2 = new Thread(new ThreadDemo(lock2, lock1), "thread-B");
        thread1.start();
        thread2.start();
    }

    /**
     * 在这个案例中，一个线程获取lock1时候第一次失败，那就等10毫秒之后第二次获取，就这样一直不停的调试，一直等到获取到相应的资源为止。
     * 当然，我们可以设置tryLock的超时等待时间tryLock(long timeout,TimeUnit unit)，
     * 也就是说一个线程在指定的时间内没有获取锁，那就会返回false，就可以再去做其他事了。
     * OK，到这里我们就把ReentrantLock常见的方法说明了，所以其原理，还是主要通过源码来解释。而且分析起来还需要集合AQS和CAS机制来分析。
     */
    static class ThreadDemo implements Runnable {
        Lock firstLock;
        Lock secondLock;

        public ThreadDemo(Lock firstLock, Lock secondLock) {
            this.firstLock = firstLock;
            this.secondLock = secondLock;
        }

        @Override
        public void run() {
            try {
                boolean tryLock1 = lock1.tryLock();
                log.info("获取锁: {}, 状态: {}", "lock1", tryLock1);
                if (!tryLock1) {

                    TimeUnit.MILLISECONDS.sleep(10);
                }
                boolean tryLock2 = lock2.tryLock();
                log.info("获取锁: {}, 状态: {}", "lock2", tryLock2);
                if (!tryLock2) {
                    TimeUnit.MILLISECONDS.sleep(10);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                log.info("释放锁: {}", "firstLock");
                firstLock.unlock();
                log.info("释放锁: {}", "secondLock");
                secondLock.unlock();
                log.info("正常结束");
            }
        }
    }
}
